using System;
using System.Linq;
using Microsoft.Maui.Controls.CustomAttributes;
using Microsoft.Maui.Controls.Internals;

#if UITEST
using NUnit.Framework;
using Xamarin.UITest;
#endif

namespace Microsoft.Maui.Controls.ControlGallery.Issues
{
#if UITEST
	[Category(Compatibility.UITests.UITestCategories.Bugzilla)]
#endif
	[Preserve(AllMembers = true)]
	[Issue(IssueTracker.Bugzilla, 33612,
		"(A) Removing a page from the navigation stack causes an 'Object reference' exception in Android only",
		PlatformAffected.Android)]
	public class Bugzilla33612 : TestNavigationPage
	{
		class Page1 : ContentPage
		{
			public Page1()
			{
				var button = new Button { Text = "Go To Page 2" };
				button.Clicked += (sender, args) => Navigation.PushAsync(new Page2());

				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "This is Page 1 - the root page" },
						button
					}
				};
			}
		}

		class FakePage : ContentPage
		{
			public FakePage()
			{
				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "This is a fake page. It will never show up." }
					}
				};
			}
		}

		class Page2 : ContentPage
		{
			public Page2()
			{
				var button = new Button { Text = "Go to Page 3" };
				button.Clicked += async (sender, args) =>
				{
					int numPagesToRemove = Navigation.NavigationStack.Count;

					Page3 page3 = new Page3();
					await Navigation.PushAsync(page3);

					var fake = new FakePage();
					Navigation.InsertPageBefore(fake, page3);

					// Remove all the previous pages on the stack (i.e., Page 1)
					// This should work fine
					for (int i = 0; i < numPagesToRemove; i++)
					{
						Page p = Navigation.NavigationStack.ElementAt(0);
						Navigation.RemovePage(p);
					}
				};

				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "This is Page 2" },
						button
					}
				};
			}
		}

		class SuccessPage : ContentPage
		{
			public SuccessPage()
			{
				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "If you're seeing this, nothing crashed. Yay!" }
					}
				};
			}
		}

		class Page3 : ContentPage
		{
			public Page3()
			{
				var button = new Button { AutomationId = "btn", Text = "Return To Page 2" };
				button.Clicked += (sender, args) =>
				{
					int numPagesToRemove = Navigation.NavigationStack.Count;

					// Remove all the previous pages on the stack 
					// Originally this would fail (and crash the app), because FakePage 
					// was never actually run through SwitchContentAsync
					// which means that it never had its renderer set.
					// But now it should work just fine
					for (int i = 0; i < numPagesToRemove - 1; i++)
					{
						Page p = Navigation.NavigationStack.ElementAt(0);
						Navigation.RemovePage(p);
					}

					var success = new SuccessPage();
					Navigation.PushAsync(success);
				};

				Content = new StackLayout()
				{
					Children = {
						new Label { Text = "This is Page 3" },
						button
					}
				};
			}
		}

		protected override void Init()
		{
			var page1 = new Page1();

			PushAsync(page1);
		}

#if UITEST
		[Test]
		[UiTest(typeof(NavigationPage))]
		public void Issue33612RemovePagesWithoutRenderers()
		{
			RunningApp.WaitForElement(q => q.Marked("Go To Page 2"));
			RunningApp.Tap(q => q.Marked("Go To Page 2"));

			RunningApp.WaitForElement(q => q.Marked("This is Page 2"));
			RunningApp.Screenshot("At Page 2");
			RunningApp.Tap(q => q.Marked("Go to Page 3"));

			RunningApp.WaitForElement("This is Page 3");
			RunningApp.WaitForElement(q => q.Marked("Return To Page 2"),
				timeout: TimeSpan.FromSeconds(15));
			RunningApp.Screenshot("At Page 3");
			RunningApp.Tap(q => q.Marked("Return To Page 2"));

			RunningApp.WaitForElement("If you're seeing this, nothing crashed. Yay!");
			RunningApp.Screenshot("Success Page");
		}
#endif
	}
}